package com.stone.redis;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
public class RedisLock {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    private DefaultRedisScript<Long> script;

    @PostConstruct
    public void init() {
        script = new DefaultRedisScript<>();
        script.setResultType(Long.class);
        script.setScriptSource(new ResourceScriptSource(new ClassPathResource("lock.lua")));
    }

    /**
     * setIfAbsent <=> SET key value [NX] [XX] [EX <seconds>] [PX [millseconds]]
     * set expire time 5 mins
     * value : UUID.randomUUID().toString().replace("-", "");  如下为使用UUID、固定字符串，固定字符串容易出现线程不安全
     */
    public Boolean getLockV1(String key, String value) {
        return redisTemplate.opsForValue().setIfAbsent(key, value, 20000, TimeUnit.MILLISECONDS);
    }

    public void unLockV1(String key) {
        redisTemplate.delete(key);
    }

    public Boolean getLockV2(String key, String value) {
        return redisTemplate.opsForValue().setIfAbsent(key, value, 20000, TimeUnit.MILLISECONDS);
    }

    public void unLockV2(String key, String value) {
        List<String> keys = new ArrayList<>();
        keys.add(key);
        Long execute = redisTemplate.execute(script, keys, value);
        System.out.println("execute 执行结果，1 表示执行 del，0 表示未执行 ===== " + execute);
        log.info("{} 解锁成功，结束处理业务", key);
    }
}
